package com.tudouji.framework.task;

import com.tudouji.common.utils.DateUtils;
import com.tudouji.project.customer.domain.Customer;
import com.tudouji.project.customer.service.ICustomerService;
import com.tudouji.project.mt.domain.MtGoodsDue;
import com.tudouji.project.mt.domain.MtShop;
import com.tudouji.project.mt.service.*;
import com.tudouji.project.organization.domain.Department;
import com.tudouji.project.organization.domain.Organization;
import com.tudouji.project.organization.domain.Supplier;
import com.tudouji.project.organization.service.IDepartmentService;
import com.tudouji.project.organization.service.IOrganizationService;
import com.tudouji.project.organization.service.ISupplierService;
import com.tudouji.project.product.domain.Salesspecification;
import com.tudouji.project.product.service.ISalesspecificationService;
import com.tudouji.project.store.domain.Stockunit;
import com.tudouji.project.store.domain.Storehouseroom;
import com.tudouji.project.store.domain.Storeroom;
import com.tudouji.project.store.service.IStockunitService;
import com.tudouji.project.store.service.IStorehouseroomService;
import com.tudouji.project.store.service.IStoreroomService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * 美团数据加工
 */
@Service
@Slf4j
public class MeituanDataProcessUtil {
    @Autowired
    private ISupplierService supplierService;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ICustomerService customerService;

    @Autowired
    private ISalesspecificationService salesspecificationService;

    @Autowired
    private IStoreroomService storeroomService;

    @Autowired
    private IStorehouseroomService storehouseroomService;

    @Autowired
    private IStockunitService stockunitService;

    @Autowired
    private IMtShopService mtShopService;

    @Autowired
    private IMtWhinService mtWhinService;
    @Autowired
    private IMtWhinitemService mtWhinitemService;

    @Autowired
    private IMtWhoutService mtWhoutService;
    @Autowired
    private IMtWhoutitemService mtWhoutitemService;
    @Autowired
    private IDepartmentService departmentService;
    @Autowired
    private IMtGoodsDueService mtGoodsDueService;

    public HashMap<Long,Organization> organizationMap = new HashMap<>();
    public HashMap<String,Supplier> supplierMap = new HashMap<>();

    public HashMap<String,Customer> customerMap = new HashMap<>();
    public HashMap<String,Storehouseroom> storehouseroomMap = new HashMap<>();
    public HashMap<String,Storeroom> storeroomMap = new HashMap<>();
    public HashMap<String,Salesspecification> salesspecificationMap = new HashMap<>();
    public HashMap<Long,Stockunit> stockunitMap = new HashMap<>();
    public HashMap<Long,Department> departmentMap = new HashMap<>();
    public HashMap<String,Customer> innerCustomerMap = new HashMap<>();
    public HashMap<String,Supplier> innerSupplierMap = new HashMap<>();

    //三方平台包括美团线下店铺、拼多多抖音等线上店铺，生成ERP订单时是否允许倒退日
    public static boolean backDate_Allowed = false;

    /*美团出入库单类型  --- 对应ERP系统入库单类型
    * 某些类型的出入库单，比如配送出入库，需要区分同组织、跨组织
    * 但有些是不需要区分的，比如采购订单，系统区分设置两种情况的对应表
    * 是否需要区分同组织、跨组织由业务调用方确认，原则上，不区分同组织、跨组织的情况
    * 下，对应关系配置在同组织映射表 sameOrgMap中
    * 注：美团同组织调拨单，ERP必须处理为其他出入库单，不能推送为ERP调拨单，因为ERP调拨单
    * 在推送金蝶的时候有特殊处理
     */
    //入库跨组织,不存在跨组织情况的入库单类型不能配置进来
    public static HashMap<Integer,Integer> whinDiffOrgMap = new HashMap<Integer,Integer>(){
        {
            put(3,9);  //美团配送收货入库，跨组织的情况下 - erp采购入库
            put(19,9);  //美团配送收货入虚拟库，跨组织的情况下 - erp采购入库
            put(6,9);  //美团调拨入库，跨组织的情况下 - erp采购入库
            put(20,9);  //配送返货驳回入库 - erp采购入库 待确认？
        }
    };
    //入库同组织
    public static HashMap<Integer,Integer> whinSameOrgMap = new HashMap<Integer,Integer>(){
        {
            put(-1,7); //默认 - ERP入库类型为 7其他入库
            put(2,9);  //美团采购入库 - erp采购入库
            put(9,9);  //美团采购入虚拟库，ERP采购入库
            put(3,10);  //美团配送收货入库，同组织 - erp调拨入库 (不可以调拨入库，必须其它入库）
            //put(19,2);  //美团配送收货入虚拟库，同组织下 - erp调拨入库 (不可以调拨入库，必须其它入库）
            put(6,11);  //美团调拨入库，同组织的情况下 - erp美团调拨入库
        }
    };
    //出库跨组织
    public static HashMap<Integer,Integer> whoutDiffOrgMap = new HashMap<Integer,Integer>(){
        {
            put(6,2);  //美团配送发货出库，跨组织的情况下 - erp销售出库
            put(11,2);  //美团配送发货出虚拟库，跨组织的情况下 - erp销售出库
            put(8,2);  //美团调拨出库，跨组织的情况下 - erp销售出库
        }
    };
    //出库同组织
    public static HashMap<Integer,Integer> whoutSameOrgMap = new HashMap<Integer,Integer>(){
        {
            put(-1,6); //默认 - ERP出库类型为 6其他出库
            //put(9,2);  //美团菜品销售出库 - erp不对应、不解析、不处理
            put(6,8);  //美团配送发货出库， - erp新增的美团配送出库
            //put(11,3);  //美团配送发货出虚拟库 - erp调拨出库 (不可以调拨出库，必须其它出库）
            put(8,7);  //美团调拨出库，同组织的情况下 - erp美团调拨出库
        }
    };

    /**
     * 根据美团入库单类型，获取ERP系统出入库库单类型
     * @param diffOrg  true 库组织 false 同组织
     * @param mtType   美团入库单类型
     * @return
     */
    public Integer getWhinErpTypeByMtType(boolean diffOrg,int mtType){
        if(diffOrg){
            return whinDiffOrgMap.get(mtType);
        }
        return whinSameOrgMap.getOrDefault(mtType,whinSameOrgMap.get(-1));
    }

    /**
     * 根据美团出库单类型，获取ERP出库单类型
     * @param diffOrg   true 跨组织 false  同组织
     * @param mtType    美团出库单类型
     * @return
     */
    public Integer getWhoutErpTypeByMtType(boolean diffOrg,int mtType){
        if(diffOrg){
            return whoutDiffOrgMap.get(mtType);
        }
        return whoutSameOrgMap.getOrDefault(mtType,whoutSameOrgMap.get(-1));
    }

    public void clearup(){
        organizationMap.clear();
        supplierMap.clear();
        customerMap.clear();
        innerSupplierMap.clear();
        innerCustomerMap.clear();
        salesspecificationMap.clear();
        storeroomMap.clear();
        storehouseroomMap.clear();
        departmentMap.clear();
        stockunitMap.clear();
    }

    /**
     * 根据OrgId获取到对应的ERP系统的内部供应商信息
     * @param organization
     * @return
     */
    protected ProcessWrapper<Supplier> findSupplierByOrg(Organization organization){
        ProcessWrapper<Supplier> result = new ProcessWrapper<>();
        if(innerSupplierMap.get(organization.getGuid())!=null){
            result.setSuccess(true);
            result.setTarget(innerSupplierMap.get(organization.getGuid()));
            return result;
        }
        //根据orgId查找对应的内部供应商
        Supplier supplierLookup = new Supplier();
        supplierLookup.setOrgguid(organization.getGuid());
        supplierLookup.setType(3);  //内部供应商
        List<Supplier> supplierList = supplierService.selectSupplierList(supplierLookup);
        if(supplierList.size()!=1){
            result.setSuccess(false);
            result.setMessage("orgName:"+organization.getName()+"对应的内部供应商配置错误");
            return result;
        }
        Supplier supplier = supplierList.get(0);
        result.setSuccess(true);
        result.setTarget(supplier);
        innerSupplierMap.put(organization.getGuid(),supplier);
        return result;
    }

    /**
     * 获取内部机构对应的客户信息
     * @param organization         内部机构
     * @return
     */
    protected ProcessWrapper<Customer> findCustomerOrg(Organization organization){
        ProcessWrapper<Customer> result = new ProcessWrapper<>();
        if(innerCustomerMap.get(organization.getGuid())!=null){
            result.setSuccess(true);
            result.setTarget(innerCustomerMap.get(organization.getGuid()));
            return result;
        }
        //根据orgId查找对应的内部客户
        Customer customerLookup = new Customer();
        customerLookup.setOrgguid(organization.getGuid());
        customerLookup.setType(2);  //内部客户
        List<Customer> customerList = customerService.selectCustomerList(customerLookup);
        if(customerList.size()!=1){
            result.setSuccess(false);
            result.setMessage("orgName:"+organization.getName()+"对应的内部客户配置错误");
            return result;
        }
        Customer customer = customerList.get(0);
        result.setSuccess(true);
        result.setTarget(customer);
        innerCustomerMap.put(organization.getGuid(),customer);
        return result;
    }

    /**
     * 获取库存单位信息，为可能的库存数量的转变做准备
     * @param stockunitid
     * @return
     */
    protected ProcessWrapper<Stockunit> processStockUnit(Long stockunitid) {
        ProcessWrapper<Stockunit> stockWrapper=new ProcessWrapper<Stockunit>();
        Stockunit stockunit = stockunitMap.get(stockunitid);
        if(stockunit !=null){
            stockWrapper.setSuccess(true);
            stockWrapper.setTarget(stockunit);
            return stockWrapper;
        }
        stockunit=stockunitService.selectStockunitById(stockunitid);
        if(stockunit == null){
            stockWrapper.setSuccess(false);
            stockWrapper.setMessage("库存单位Id:"+stockunitid+" 没有对应的配置信息！");
            return stockWrapper;
        }
        stockWrapper.setSuccess(true);
        stockWrapper.setTarget(stockunit);
        return stockWrapper;
    }

    /**
     * 根据美团物品编码获取ERP物料信息
     * @param goodsCode
     * @param mtShop
     * @return
     */
    protected ProcessWrapper<Salesspecification> processSalesSpec(String goodsCode, MtShop mtShop) {
        ProcessWrapper<Salesspecification> spWrapper=new ProcessWrapper<Salesspecification>();
        Salesspecification salesspecification = salesspecificationMap.get(goodsCode);
        if(salesspecification !=null){
            spWrapper.setSuccess(true);
            spWrapper.setTarget(salesspecification);
            return spWrapper;
        }
        getSaleSpByMtCode(goodsCode,spWrapper);
        return spWrapper;
    }

    /**
     * 根据美团物品code，获取对应的ERP物料 from database
     * @param goodsCode
     * @param spWrapper
     */
    protected boolean getSaleSpByMtCode(String goodsCode, ProcessWrapper<Salesspecification> spWrapper) {
        Salesspecification lookup = new Salesspecification();
        lookup.setMtSkuid(goodsCode);
        List<Salesspecification> spList = salesspecificationService.selectSalesspecificationList(lookup);
        //20240121 通过美团物料CODE查询替代料
        if (spList.size() == 0){
            MtGoodsDue goodsDue = new MtGoodsDue();
            goodsDue.setMtGoodsCodeDue(goodsCode);
            List<MtGoodsDue> goodsDueList = mtGoodsDueService.selectMtGoodsDueList(goodsDue);
            if(spList.size()!=1){
                log.info(goodsCode+" - 对应的物料信息设置不正确："+goodsDueList.size());
                spWrapper.setSuccess(false);
                spWrapper.setMessage(goodsCode+" - 对应的物料信息设置不正确："+goodsDueList.size());
                return false;
            }
            goodsCode = goodsDueList.get(0).getMtGoodsCode();
            lookup.setMtSkuid(goodsCode);
            spList = salesspecificationService.selectSalesspecificationList(lookup);
        }
        if(spList.size()!=1){
            log.info(goodsCode+" - 对应的物料信息设置不正确："+spList.size());
            spWrapper.setSuccess(false);
            spWrapper.setMessage(goodsCode+" - 对应的物料信息设置不正确："+spList.size());
            return false;
        }
        Salesspecification salesspecification = spList.get(0);

        spWrapper.setSuccess(true);
        spWrapper.setTarget(salesspecification);
        salesspecificationMap.put(goodsCode,salesspecification);
        return true;
    }

    /**
     * 根据美团库房编码，获取ERP系统库房及库间信息
     * @param mtWarehouseCode
     * @param mtShop
     * @return
     */
    protected ProcessWrapper processWareHouse(String mtWarehouseCode, MtShop mtShop,Salesspecification salesspecification) {
        ProcessWrapper<Storehouseroom> wareHouseWrapper = new ProcessWrapper<>();
        Storehouseroom storehouseroom=storehouseroomMap.get(mtWarehouseCode);
        if(storehouseroom!=null) {
            wareHouseWrapper.setSuccess(true);
            wareHouseWrapper.setTarget(storehouseroom);
            return wareHouseWrapper;
        }
        getStoreHouseroomByMtCode(mtWarehouseCode, wareHouseWrapper,salesspecification);
        return wareHouseWrapper;
    }

    /**
     * 根据美团库房code获取到ERP系统对应的库间,如果美团物料涉及到ERP系统的多个类型的物料（原料、成品、辅料、半成品）的话，
     * 美团门店下的库房code对应ERP系统该门店下的多个库间（多个库间设置为同一个美团库房code）
     * 此方法遍历美团库房code对应的erp库间，查找到与当前物料类型匹配的库间
     * @param mtWarehouseCode
     * @return
     */
    private boolean getStoreHouseroomByMtCode(String mtWarehouseCode, ProcessWrapper wareHouseWrapper,Salesspecification salesspecification) {
        Storehouseroom lookup = new Storehouseroom();
        lookup.setMtWhCode(mtWarehouseCode);
        Storehouseroom storehouseroom = null;
        List<Storehouseroom> storehouseroomList = storehouseroomService.selectStorehouseroomList(lookup);
        for(Storehouseroom shr:storehouseroomList){
            if(shr.getShrtype().intValue()==salesspecification.getType().intValue()){
                storehouseroom = shr;
                break;
            }
        }

        if(storehouseroom==null){
            log.info(mtWarehouseCode+" - 对应的库间信息设置不正确：");
            wareHouseWrapper.setSuccess(false);
            wareHouseWrapper.setMessage(mtWarehouseCode+" - 找不到物料对应的库间信息："+salesspecification.getType());
            return false;
        }
        Storeroom storeroom = storeroomService.selectStoreroomByGuid(storehouseroom.getStoreguid());
        wareHouseWrapper.setSuccess(true);
        wareHouseWrapper.setTarget(storehouseroom);
        storehouseroomMap.put(mtWarehouseCode,storehouseroom);
        storeroomMap.put(mtWarehouseCode,storeroom);
        return true;
    }


    /**
     * 获取部门信息
     * @param mtShop
     * @return
     */
    protected ProcessWrapper<Department> getDepartment(MtShop mtShop) {
        ProcessWrapper<Department> result = new ProcessWrapper<>();
        Department department = departmentMap.get(mtShop.getDeptId());
        if(department!=null){
            result.setSuccess(true);
            result.setTarget(department);
            return result;
        }
        Department lookup = new Department();
        lookup.setId(mtShop.getDeptId());
        department = departmentService.selectDepartmentByAutoId(mtShop.getDeptId());
        if(department==null){
            result.setSuccess(false);
            result.setMessage("店铺表设置的部门错误！");
            return result;
        }
        result.setSuccess(true);
        result.setTarget(department);
        return result;
    }

    /**
     * 根据美团供应商编号，获取ERP系统供应商
     * @param supplierCode
     * @return
     */
    protected ProcessWrapper getSupplier(String supplierCode) {
        ProcessWrapper<Supplier> result= new ProcessWrapper<>();
        Supplier supplier = supplierMap.get(supplierCode);
        if(supplier!=null){
            result.setSuccess(true);
            result.setTarget(supplier);
            return result;
        }

        Supplier lookup = new Supplier();
        lookup.setMtCode(supplierCode);
        List<Supplier> supplierList = supplierService.selectSupplierList(lookup);
        if(supplierList.size()!=1){
            result.setSuccess(false);
            result.setMessage("供应商编码没有设置或设置错误");
            return result;
        }
        supplier=supplierList.get(0);
        supplierMap.put(supplierCode,supplier);
        result.setSuccess(true);
        result.setTarget(supplier);
        return result;
    }

    /**
     * 获取客户信息
     * @param mtShop
     * @return
     */
    protected Customer getCustomer(MtShop mtShop) {
        Customer customer=null;
        customer = customerMap.get(mtShop.getCustomerId());
        if(customer!=null){
            return customer;
        }
        //customer = customerService.selectCustomerById(mtShop.getCustomerId());
        //需要有一个根据自增id获取customer的方法
        customerMap.put(customer.getGuid(),customer);
        return customer;
    }

    /**
     * 获取店铺对应的ERP组织信息
     * @param mtShop
     * @return
     */
    public Organization getOrgnization(MtShop mtShop) {
        Organization organization=null;
        organization = organizationMap.get(mtShop.getOrgId());
        if(organization!=null){
            return organization;
        }
        organization = organizationService.selectOrganizationByAutoId(mtShop.getOrgId());
        organizationMap.put(organization.getId(),organization);
        return organization;
    }

    /**
     * 通过美团机构的code获取对应的ERP机构信息
     * @param mt_orgCode    美团机构code
     */
    public ProcessWrapper<Organization> getOrgByMtcode(String mt_orgCode) {
        ProcessWrapper<Organization> result = new ProcessWrapper<>();

        MtShop mtShop = new MtShop();
        mtShop.setMtOrgcode(mt_orgCode);
        List<MtShop> mtShopList = mtShopService.selectMtShopList(mtShop);
        if(mtShopList.size()!=1){
            result.setSuccess(false);
            result.setMessage("美团组织编号："+mt_orgCode+"对应的店铺信息设置错误！");
            return result;
        }
        Organization organization = organizationService.selectOrganizationByAutoId(mtShopList.get(0).getOrgId());

        /*Organization lookup = new Organization();
        lookup.setMtCode(mt_orgCode);
        List<Organization> organizationList = organizationService.selectOrganizationList(lookup);
        if(organizationList.size()!=1){
            result.setSuccess(false);
            result.setMessage("美团组织编号："+mt_orgCode+"对应的机构信息设置错误！");
            return result;
        }
        Organization organization = organizationList.get(0);*/
        result.setSuccess(true);
        result.setTarget(organization);
        return result;
    }


    /**
     * 调用包装类
     */
    @Data
    public class ProcessWrapper<T> {
        private T target;
        private boolean success;
        private String message;
    }

    /**
     * 根据财务要求，记录三方平台的业务日期、或ERP平台业务日期（订单推送过来之后ERP系统的入库日期）
     * @param startDate   批量时传入开始日期（本次业务处理的开始日期）,联机时传入plantform_loadDate
     * @param endDate    批量时传入截止日期  联机时传入plantform_loadDate
     * @param tranType   1 -- 批量调用  2 -- 联机，入库或返入库交易调用
     * @param kdClosingDay   金蝶结账日，一般是2号
     * @return
     */
    public static Date getLoadingTime(@NotNull Date startDate, Date endDate, int tranType, int kdClosingDay){
        Calendar today = Calendar.getInstance(java.util.Locale.CHINA);
        today.setTime(DateUtils.getNowDate());
        if(tranType ==1){
            //如果不倒推的话，直接返回EndDate
            if(!backDate_Allowed){
                return endDate;
            }
            //2号以后的批量交易（电商平台生成销售订单），直接返回endDate
            log.info("today dayofmonth:"+ today.get(Calendar.DAY_OF_MONTH));
            if(today.get(Calendar.DAY_OF_MONTH) > kdClosingDay ){
                return endDate;
            }else{
                //2号以前的（包括2号），判断跨月则返回开始日期的月末
                if (!DateUtils.isSameYearAndMonth(startDate, endDate)){
                    log.info("diff month here");
                    Date lastDayOfPreMonth = DateUtils.getLastDayOfPreMonth();
                    if(lastDayOfPreMonth.getTime()>endDate.getTime()){
                        return endDate;
                    }
                    return lastDayOfPreMonth;
                }else{
                    log.info("same month here");
                    return endDate;
                }
            }
        }
        //联机调用
        //不倒推的话直接返回当天日期
        if(!backDate_Allowed){
            return today.getTime();
        }
        if(today.get(Calendar.DAY_OF_MONTH) > kdClosingDay ){
            //2号以后的出入库交易，不倒推的话，返回当前日期，否则，返回startDate
            //目前暂时不倒推
            return today.getTime();
        }else{
            //2号以前的出入库交易，倒推记录，返回传入的startDate
            return startDate;
        }
    }

}
